<template>
    <teleport to="body">
        <div class="a-modal c-position-fixed c-left-top c-s-100 c-f-h" :class="props.placement" ref="popRef" v-if="value">
            <slot></slot>
        </div>
    </teleport>
</template>

<style lang="scss" scoped>
.a-modal {
    background-color: rgba(0, 0, 0, 0.2);

    &.top-left {
        justify-content: flex-start;
        align-items: flex-start;
    }

    &.top-center {
        justify-content: space-around;
        align-items: flex-start;
    }

    &.top-right {
        justify-content: flex-end;
        align-items: flex-start;
    }

    &.center-left {
        justify-content: flex-start;
        align-items: center;
    }

    &.center-center {
        justify-content: center;
        align-items: center;
    }

    &.center-right {
        justify-content: flex-end;
        align-items: center;
    }

    &.bottom-left {
        justify-content: flex-start;
        align-items: flex-end;
    }

    &.bottom-center {
        justify-content: center;
        align-items: flex-end;
    }

    &.bottom-right {
        justify-content: flex-end;
        align-items: flex-end;
    }
}
</style>

<script setup lang="ts">
import popIdUtil from "@/common/popIdUtil"
import utils from '@/common/utils'
import { ModalPlacementType } from '@/types'
import { nextTick, onUnmounted, reactive, ref, watch } from 'vue'

const emit = defineEmits<{
    (e: 'update:value', value: boolean): void
}>()

interface PropsType {
    value?: boolean
    clickBgToClose?: boolean
    escToClose?: boolean
    placement?: ModalPlacementType
}
const props = withDefaults(defineProps<PropsType>(), {
    value: false,
    clickBgToClose: false,
    escToClose: true,
    placement: 'center-center',
})

interface StateType {
    popId?: number
}
const state = reactive<StateType>({
    popId: undefined
})

watch(() => props.value, () => {
    if (props.value) {
        methods.onPopShown()
    } else {
        methods.onPopHidden()
    }
})

onUnmounted(() => {
    methods.onPopHidden()
})

const popRef = ref<HTMLDivElement>()
const methods = {
    getPopEl() {
        return utils.getEl(popRef.value)
    },
    getContentEl() {
        return methods.getPopEl()?.children[0]
    },
    addEventListener() {
        let popEl = methods.getPopEl()!
        popEl.addEventListener('click', methods.onBgClick)

        if (props.escToClose) {
            window.document.addEventListener('keydown', methods.onDocumentKeydown)
        }
    },
    removeEventListener() {
        if (props.escToClose) {
            window.document.removeEventListener('keydown', methods.onDocumentKeydown)
        }
    },
    onBgClick(e: MouseEvent) {
        if (!props.clickBgToClose) {
            return
        }
        let contentEl = methods.getContentEl()
        if (!contentEl) {
            return
        }
        if (
            contentEl.contains(e.target as Node)
            || !window.document.contains(e.target as Node)
        ) {
            return
        }
        methods.hideModal()
    },
    onDocumentKeydown(e: KeyboardEvent) {
        if (e.keyCode === 27 && popIdUtil.isTop(state.popId!)) {
            methods.hideModal()
        }
    },
    showModal() {
        emit('update:value', true)
    },
    hideModal() {
        emit('update:value', false)
    },
    onPopShown() {
        if (props.escToClose) {
            state.popId = popIdUtil.create()
        }
        nextTick(() => {
            methods.addEventListener()
        })
    },
    onPopHidden() {
        methods.removeEventListener()

        popIdUtil.remove(state.popId!)
    },
}
</script>